package com.vvv.designpattern.service;

import com.vvv.designpattern.dutychain.AbstractBusinessHandler;
import com.vvv.designpattern.dutychain.CityHandler;
import com.vvv.designpattern.dutychain.builder.HandlerEnum;
import com.vvv.designpattern.pojo.BusinessLaunch;
import com.vvv.designpattern.pojo.UserInfo;
import com.vvv.designpattern.repo.BusinessLaunchRepository;
import com.vvv.designpattern.repo.UserRepository;
import com.vvv.designpattern.ticket.proxy.DirectorProxy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author vvv
 * @date 2023-11-14 15 11
 * discription
 */
@Service
public class UserService {
    @Resource
    private UserRepository userRepository;

    @Resource
    private BusinessLaunchRepository businessLaunchRepository;
    /**
     * apollo上的配置的责任链顺序，如city,sex,product
     */
    @Value("${duty.chain}")
    private String handleType;
    /**
     * 当前的责任链顺序
     */
    private String currentHandlerType;
    /**
     * 当前的责任链的头结点
     */
    private AbstractBusinessHandler currentHandler;
    /**
     * 创链锁
     */
    public static final ReentrantLock businessLaunchBuilderLock = new ReentrantLock();

    @Resource
    private DirectorProxy directorProxy;

    /**
     * 业务投放
     * @param city
     * @param sex
     * @param product
     * @return
     */
    public List<BusinessLaunch> filterBusinessLaunch(String city, String sex, String product) {
        // 1. 从数据库中获取全部的业务投放数据
        List<BusinessLaunch> launchList = businessLaunchRepository.findAll();
        // 2. 通过redis中获取用户的city sex 和 product
        // 3. 构建责任链并调用
        return buildChain().processHandler(launchList, city, sex, product);
    }

    /**
     * 责任链的装配者，使用者
     * @return
     */
    private AbstractBusinessHandler buildChain() {
        // 1. 如果apollo中没有配置链的顺序直接报错
        if (handleType == null) {
            throw new UnsupportedOperationException("please configure the business launch order in apollo first !");
        }
        // 2. 如果handleType == currentHandlerType，说明没有修改，直接返回currentHandler
        if (handleType.equals(currentHandlerType) && currentHandler != null) {
            return currentHandler;
        }
        // 3. 第一次创链或者配置被修改
        System.out.println("配置有修改或者首次初始化，开始组装责任链！！！");
        // 3.1 lock + double check
        businessLaunchBuilderLock.lock();
        try {
            // double check
            if (handleType.equals(currentHandlerType) && currentHandler != null) {
                return currentHandler;
            }
            AbstractBusinessHandler dummyHead = new CityHandler();
            AbstractBusinessHandler pre = dummyHead;
            List<String> handlerTypeList = Arrays.asList(handleType.split(","));
            // 3.2 将链组合在一起
            for (String handlerType : handlerTypeList) {
                // 3.3 根据handleType创建AbstractBusinessHandler链对象
                AbstractBusinessHandler handler = (AbstractBusinessHandler) Class.forName(
                                    HandlerEnum.valueOf(handlerType).getValue()).newInstance();
                pre.nextHandler = handler;
                pre = handler;
            }
            // 3.4 将链头保存至currentHandler
            this.currentHandler = dummyHead.nextHandler;
            this.currentHandlerType = handleType;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            businessLaunchBuilderLock.unlock();
        }
        // 5. 返回链头
        return currentHandler;
    }

    public String login(String account, String password) {
        UserInfo userInfo = userRepository.findByUserNameAndUserPassword(account, password);
        if (userInfo == null) {
            return "account / password ERROR!";
        }
        return "Login Success";
    }

    public String register(UserInfo userInfo) {
        // TODO 这里可用布隆过滤器来先做一个判断先
        if (checkUserExists(userInfo.getUserName())) {
            throw new RuntimeException("User already registered");
        }
        userInfo.setCreateDate(new Date());
        userRepository.save(userInfo);
        return "Register Success";
    }

    public boolean checkUserExists(String userName) {
        UserInfo userInfo = userRepository.findByUserName(userName);
        if (userInfo == null) {
            return false;
        }
        return true;
    }

    public Object createTicket(String type, String productId
            , String content, String title, String bankInfo, String taxId) {
        return directorProxy.buildTicket(type, productId, content, title, bankInfo, taxId);
    }
}
